﻿using System;

namespace Course1
{
    /*
     * 1.抽象和具体
     *  类相对于实列来说，类是抽象的，实列是具体的。好比学生和张三之间，张三（实列）是具体的，学生（类）是抽象的
     *  类和类直接也存在抽象和具体：动物相对于猫狗而言，动物更加抽象，猫狗相对具体
     * 2.接口
     *  接口是标准是规范，是更加抽象的
     *  接口中只能抽象的实列成员，必须是public的
     *  接口中不存在静态成员的概念
     *  接口可以实现其他接口
     * 3.抽象类
     *   抽象类可以继承其他类或抽象类，但只能继承一个类或抽象类，但是可以实现n个接口
     *   抽象类可以用于类的所有特征，包括静态的和实列的，但是抽象类不能实例化（new）
     *   抽象类中可以定义抽象方法来间接实现接口，也可能直接实现接口
     *   抽象类相对于接口更加具体
     * 4.用接口还是抽象类
     *   建立规范出来接口，因为一个类可以实现n个接口，给实现方提供更多的可能性。
     *   一个类只能继承一个抽象类或者类。
     * 5.接口的优缺点
     *   优点：支持多实现，直观，优美
     *   缺点：没有任何实现，对于负责的业务无需从0开始写
     * 6.抽象类的优缺点
     *   优点：可以选择性的实现，给实现放提供便利，简化别人实现的成本。
     *   缺点：一个类只能继承一个抽象类
     * 7.尝试阅读源码
     * 8.强制类型转换
     *   特点：绕过编译器的类型检查
     *   值类型：可能会发生存储结构的改变，比如double到int，失败会造成精度损失
     *   引用类型：由于指针的类型都是一样的存储方式也相同，所以从一种类型到另一种类型，只改变了编译器的类型检查行为。
     *            失败可能会导致后续的代码运行异常，存在安全隐患。需要做类型转换检查。
     *   is:用于判断是否可以安全的进行强制类型转换，即是否存在继承关系
     *   string a = null;
     *   bool flag = a is object;//返回true表示可以，否则不行
     *   as:用于安全的进行强制类型转换
     *   string a = null;
     *   object obj = a as object;//返回null，表示不行，非null可以
     *   if(a is object obj)//语法糖，如果if成立，则obj保存了a的值。
     *   {
     *   
     *   }
     */
    /// <summary>
    /// 哺乳动物
    /// </summary>
    public interface IMammal
    {
        void Eat(IMammalFood food);
    }
    /// <summary>
    /// 卵生动物
    /// </summary>
    public interface IOviparity
    {
        void Eat(IOviparityFood food);
    }
    public interface IAnimal
    {
        string Name { get; }
    }
    /// <summary>
    /// 抽象类
    /// 可以定义方法的实现，也可以定义抽象方法
    /// </summary>
    public abstract class Animal: IAnimal
    {
        public string Name { get; }

        public virtual void Sleep()
        {
            Console.WriteLine(Name+"在睡觉");
        }
        /// <summary>
        /// 抽象类可以选择性实现或者留给子类实现
        /// </summary>
        /// <param name="animal"></param>
        public static void Feed(IAnimal animal)
        {
            if (animal is IMammal)//对实列的特征进行判断
            {
                Console.WriteLine("生下来就能吃奶了");
            }
            if (animal is IOviparity)//对实列的特征进行判断
            {
                Console.WriteLine("生下是一个蛋");
            }
        }

        public Animal(string name)
        {
            Name = name;
        }

    }
    public interface IFood
    {
        public string Name { get; set; }
    }
    /// <summary>
    /// 哺乳动物食物
    /// </summary>
    public interface IMammalFood : IFood
    {

    }
    /// <summary>
    /// 卵生动物食物
    /// </summary>
    public interface IOviparityFood : IFood
    {

    }
    /// <summary>
    /// 肉
    /// </summary>
    public class Meat : IMammalFood
    {
        public string Name { get; set; }

        public Meat(string name)
        {
            Name = name;
        }
    }
    /// <summary>
    /// 小米
    /// </summary>
    public class Rice : IOviparityFood, IMammalFood
    {
        public string Name { get; set; }

        public Rice(string name)
        {
            Name = name;
        }

        /// <summary>
        /// 哺乳动物特征
        /// </summary>
        public interface IMammal
        {
            void Eat(IFood food);
        }

        /// <summary>
        /// 卵生动物特征
        /// </summary>
        public interface IOviparity
        {

        }

    }
    public class Dog : Animal, IMammal
    {
        public Dog(string name) : base(name)
        {
        }

        public void Eat(IMammalFood food)
        {
            Console.WriteLine("狗爱吃：" + food.Name);
        }
       
    }
    public class Chicken : Animal, IOviparity
    {
        public Chicken(string name) : base(name)
        {
        }

        public void Eat(IOviparityFood food)
        {
            Console.WriteLine("狗爱吃：" + food.Name);
        }
      
    }
    internal class Example4
    {
        public void Test1()
        {
            var dog = new Dog("旺财");
            var chicken = new Chicken("老母鸡");
            var food1 = new Rice("米饭");
            var food2 = new Meat("鸡肉");
            dog.Eat(food1);
            chicken.Eat(food1);
            dog.Eat(food2);
            //chicken.Eat(food2);
            Animal.Feed(dog);
            Animal.Feed(chicken);
        }

        /// <summary>
        /// 多态
        /// 父类型的引用可以指向子类型的对象，表现父类型的特征（编译行为，可以用强制类型转换实现），反过来不行
        /// 如果子类型引用保存父类的的对象(强制类型转换)，虽然可以表现出父类型的特征，但是运行时会引发异常。
        /// 编译时类型：与引用相关
        /// 运行时类型：与实列相关
        /// 如果强制把一个父类型的对象或者没有继承关系的对象强制转换赋值给其他引用将引发异常。
        /// </summary>
        public void Test2()
        {
            //父类的引用指向子类型的对象
            Person obj1 = new Student();//此时obj的编译时类型为person表现出人的特征
            obj1.Sleep();
            //子类型的引用指向子类型的对象。
            Student student = (Student)obj1;
            student.GoToShcool();
        }

        public void Test3()
        {
            //父类的引用指向子类型的对象
            //obj指向的是student类型的对象
            Person obj1 = new Student();//此时obj的编译时类型为person表现出人的特征
            obj1.Sleep();
            //子类型的引用指向子类型的对象。
            //teacher指向obj1指向的对象，即student类型的对象
            Teacher teacher = (Teacher)obj1;
            teacher.Teaching();//报错，因为teacher指向的对象是Student类型，即teacher的运行时类型是student
            /**
             * 总结：
             * 强制类型转换可以改变指针的类型，但是改变不了对象的实际结构，只能欺骗编译器，无法欺骗clr（jvm）
             */
        }

        public abstract class Person
        {
            public abstract void Sleep();
        }

        public class Student: Person
        {
            public void GoToShcool()
            {
                
            }

            public override void Sleep()
            {
               
            }
        }

        public class Teacher : Person
        {
            public void Teaching()
            {

            }

            public override void Sleep()
            {

            }
        }
    }
}
